Skip to content

Comments

fix: resolve undefined {CANCEL_URL} in workflow templates#23476

Merged
anikdhabal merged 9 commits intocalcom:mainfrom
ShashwatPS:shashwatps-undefinedFix
Sep 4, 2025
Merged

fix: resolve undefined {CANCEL_URL} in workflow templates#23476
anikdhabal merged 9 commits intocalcom:mainfrom
ShashwatPS:shashwatps-undefinedFix

Conversation

@ShashwatPS
Copy link
Contributor

@ShashwatPS ShashwatPS commented Aug 31, 2025

What does this PR do?

When using the {CANCEL_URL} variable in the workflow for seated bookings, the scheduleWorkflowReminders function was called directly for the first seat, and the template worked fine. However, for subsequent seats, the handleSeats function (in packages/features/bookings/lib/handleSeats/handleSeats.ts), inside which scheduleWorkflowReminders was being called, did not pass the event’s uid. This uid was required to construct the cancel URL.

While fixing this, I also discovered that seatReferenceUid was being set incorrectly and fixed that as well.

Visual Demo

A booking with 2 seats
Screenshot 2025-08-31 at 1 02 07 PM
Screenshot 2025-08-31 at 1 02 22 PM

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

Files Modified

packages/features/bookings/lib/handleSeats/handleSeats.ts

How should this be tested?

  • Run the project locally
  • Create a new event type
  • Under the Advanced tab, enable Offer seats
  • Set the seat limit to 2
  • Disable show the number of available seats
  • Save
  • Under the Workflows tab, create a new workflow
  • Set this workflow to trigger When new event is booked
  • Set the email body to '{CANCEL_URL}'
  • Save
  • Book a slot on an email (not the email that created the Event Type)
  • Check that email account's inbox and observe that the url shows up properly.
  • Book that same slot (time and data) on a different account
  • Check that email account's inbox and observe that the link shows up with an unidentified undefined in the url

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked that my changes generate no new warnings

@ShashwatPS ShashwatPS requested a review from a team as a code owner August 31, 2025 07:36
@vercel
Copy link

vercel bot commented Aug 31, 2025

@ShashwatPS is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 31, 2025

Walkthrough

Adds seatedBooking.uid into the calendarEvent payload passed to scheduleWorkflowReminders and switches the seatReferenceUid used when scheduling reminders from evt.attendeeSeatId to resultBooking?.seatReferenceUid in packages/features/bookings/lib/handleSeats/handleSeats.ts. In packages/features/ee/workflows/lib/reminders/emailReminderManager.ts, introduces an isEmailAttendeeAction flag to: include seatReferenceUid in cancel and reschedule URLs for attendee-targeted EMAIL_ATTENDEE actions and to select attendee locale for those emails. No public signatures were changed.

Assessment against linked issues

Objective Addressed Explanation
Ensure {CANCEL_URL} in workflow emails resolves to the correct booking for seated bookings, including subsequent bookers (#22572, CAL-6113)

Out-of-scope changes

( none identified )

Possibly related PRs


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5f38d8e and a16773d.

📒 Files selected for processing (1)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Aug 31, 2025
@github-actions github-actions bot added emails area: emails, cancellation email, reschedule email, inbox, spam folder, not getting email Low priority Created by Linear-GitHub Sync workflows area: workflows, automations 🐛 bug Something isn't working labels Aug 31, 2025
@graphite-app graphite-app bot requested a review from a team August 31, 2025 07:36
@dosubot dosubot bot added the bookings area: bookings, availability, timezones, double booking label Aug 31, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d44a41c and c9f5c71.

📒 Files selected for processing (1)
  • packages/features/bookings/lib/handleSeats/handleSeats.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/bookings/lib/handleSeats/handleSeats.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/bookings/lib/handleSeats/handleSeats.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/bookings/lib/handleSeats/handleSeats.ts
🧬 Code graph analysis (1)
packages/features/bookings/lib/handleSeats/handleSeats.ts (1)
packages/features/ee/workflows/lib/reminders/reminderScheduler.ts (1)
  • scheduleWorkflowReminders (395-398)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (2)
packages/features/bookings/lib/handleSeats/handleSeats.ts (2)

132-132: Seat reference wiring depends on Line 111 fix.

Passing seatReferenceUid: currentAttendeeSeatId is correct only if Line 111 sources it from resultBooking?.seatReferenceUid. Please update Line 111 accordingly; otherwise reminders for later seats will still reference the wrong attendee.

After the change, validate by booking 2 seats and inspecting each email/link target.


117-117: Prefer the updated booking UID for CANCEL_URL

-          uid: seatedBooking.uid,
+          uid: resultBooking?.uid ?? seatedBooking.uid,

@anikdhabal
Copy link
Contributor

@ShashwatPS pls check this and try to address it here:- #22572 (comment)

@ShashwatPS ShashwatPS requested a review from anikdhabal August 31, 2025 16:54
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)

163-166: URL-encode seatReferenceUid when appending to cancelLink

Avoid malformed links if the UID ever contains reserved characters.

Apply this minimal patch:

-      }${seatReferenceUid ? `&seatReferenceUid=${seatReferenceUid}` : ""}`,
+      }${seatReferenceUid ? `&seatReferenceUid=${encodeURIComponent(seatReferenceUid)}` : ""}`,

Optional: consider building these URLs with URL/URLSearchParams to remove string-concat edge cases.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9b423c5 and 5e053b1.

📒 Files selected for processing (1)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache

anikdhabal
anikdhabal previously approved these changes Sep 1, 2025
Copy link
Contributor

@anikdhabal anikdhabal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

anikdhabal
anikdhabal previously approved these changes Sep 1, 2025
@anikdhabal anikdhabal enabled auto-merge (squash) September 1, 2025 02:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)

164-167: URL-encode seatReferenceUid and prefer a params builder.

seatReferenceUid should be encoded; also consider URLSearchParams to keep both links robust and consistent.

Minimal encoding tweak:

-      }${isEmailAttendeeAction && seatReferenceUid ? `&seatReferenceUid=${seatReferenceUid}` : ""}`,
+      }${isEmailAttendeeAction && seatReferenceUid ? `&seatReferenceUid=${encodeURIComponent(seatReferenceUid)}` : ""}`,

Cleaner alternative (add just above const variables):

const cancelUrl = new URL(`${bookerUrl}/booking/${evt.uid}`);
cancelUrl.searchParams.set("cancel", "true");
if (recipientEmail) cancelUrl.searchParams.set("cancelledBy", recipientEmail);
if (isEmailAttendeeAction && seatReferenceUid) cancelUrl.searchParams.set("seatReferenceUid", seatReferenceUid);

const rescheduleUrl = new URL(`${bookerUrl}/reschedule/${evt.uid}`);
if (recipientEmail) rescheduleUrl.searchParams.set("rescheduledBy", recipientEmail);
if (isEmailAttendeeAction && seatReferenceUid) rescheduleUrl.searchParams.set("seatReferenceUid", seatReferenceUid);

Then inside variables:

cancelLink: cancelUrl.toString(),
rescheduleLink: rescheduleUrl.toString(),
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5e053b1 and 31b177f.

📒 Files selected for processing (1)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
🧠 Learnings (1)
📚 Learning: 2025-08-27T16:39:38.156Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.156Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.

Applied to files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
🔇 Additional comments (2)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (2)

143-143: Nice readability win with isEmailAttendeeAction.

Clearer than repeating the comparison.


180-182: Align locale usage across template and custom-email flows
In emailReminderManager.ts the REMINDER/RATING template calls still use evt.organizer.language.locale while only the custom-body path switches to attendee.language?.locale. Confirm whether the default templates should also use the attendee’s locale for parity.

Copy link
Contributor

@anikdhabal anikdhabal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (3)

183-186: Use the selected attendee’s timezone consistently

These variables should reflect the timezone of attendeeToBeUsedInMail (which may not be attendees[0] for EMAIL_ATTENDEE).

-      attendeeTimezone: evt.attendees[0].timeZone,
-      eventTimeInAttendeeTimezone: dayjs(startTime).tz(evt.attendees[0].timeZone),
-      eventEndTimeInAttendeeTimezone: dayjs(endTime).tz(evt.attendees[0].timeZone),
+      attendeeTimezone: attendeeToBeUsedInMail.timeZone,
+      eventTimeInAttendeeTimezone: dayjs(startTime).tz(attendeeToBeUsedInMail.timeZone),
+      eventEndTimeInAttendeeTimezone: dayjs(endTime).tz(attendeeToBeUsedInMail.timeZone),

419-431: Limit Prisma fetch to required fields

Only uuid and referenceId are used; select them explicitly.

-  const workflowReminder = await prisma.workflowReminder.findUnique({
-    where:
-      { id: reminderId },
-  });
+  const workflowReminder = await prisma.workflowReminder.findUnique({
+    where: { id: reminderId },
+    select: { uuid: true, referenceId: true },
+  });

164-178: Optional: build links with URL/URLSearchParams to avoid ternaries

Consider constructing both links with URLSearchParams to simplify branching and ensure encoding across all params.

Example sketch (not a drop-in):

const cancel = new URL(`${bookerUrl}/booking/${evt.uid}`);
const cancelQs = new URLSearchParams({ cancel: "true" });
if (recipientEmail) cancelQs.set("cancelledBy", recipientEmail);
if (isEmailAttendeeAction && seatReferenceUid) cancelQs.set("seatReferenceUid", seatReferenceUid);
const cancelLink = `${cancel.pathname}?${cancelQs.toString()}`;

const res = new URL(`${bookerUrl}/reschedule/${evt.uid}`);
const resQs = new URLSearchParams();
if (recipientEmail) resQs.set("rescheduledBy", recipientEmail);
if (isEmailAttendeeAction && seatReferenceUid) resQs.set("seatReferenceUid", seatReferenceUid);
const rescheduleLink = resQs.toString() ? `${res.pathname}?${resQs.toString()}` : res.pathname;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 31b177f and 5f38d8e.

📒 Files selected for processing (1)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
🧠 Learnings (1)
📚 Learning: 2025-08-27T16:39:38.156Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.156Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.

Applied to files:

  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (4)

143-143: Good guard for attendee-specific behavior

Using a single isEmailAttendeeAction flag centralizes attendee-specific logic and reduces repeat conditionals. LGTM.


169-178: Reschedule link query-string fix looks correct

Nice job handling the leading “?” vs “&” and encoding seatReferenceUid. This resolves the earlier edge case where recipientEmail was falsy.


298-311: Store seatReferenceId for SMTP/tasker-scheduled reminders as well

Other branches persist seatReferenceId; this one doesn’t. For consistency and seat-scoped operations, persist it here too.

       if (scheduledDate) {
         const reminder = await prisma.workflowReminder.create({
           data: {
             bookingUid: uid,
             workflowStepId,
             method: WorkflowMethods.EMAIL,
             scheduledDate: scheduledDate.toDate(),
             scheduled: true,
+            seatReferenceId: seatReferenceUid,
           },
         });

Would you confirm whether downstream consumers expect seatReferenceId for SMTP-scheduled reminders?


188-190: Locale switch based on action is appropriate

Choosing attendee locale for EMAIL_ATTENDEE and organizer otherwise is the right UX. LGTM.

@github-actions
Copy link
Contributor

github-actions bot commented Sep 3, 2025

E2E results are ready!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bookings area: bookings, availability, timezones, double booking 🐛 bug Something isn't working community Created by Linear-GitHub Sync emails area: emails, cancellation email, reschedule email, inbox, spam folder, not getting email Low priority Created by Linear-GitHub Sync ready-for-e2e size/S workflows area: workflows, automations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Workflow {CANCEL_URL} gives undefined booking in link

3 participants